package org.springframework.aop.framework;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/****
 * 自定义一个调用链
 *
 */
public class A18_1 {
	 static class Target {
	        public void foo() {
	            System.out.println("Target.foo()");
	        }
	    }

	 
	 /***
	  * 定义一个切面  实现invoke方法   在这个方法中在调用拦截器的proceed方法
	  */
	    static class Advice1 implements MethodInterceptor {
	        public Object invoke(MethodInvocation invocation) throws Throwable {
	            System.out.println("Advice1.before()");
	            Object result = invocation.proceed();// 调用下一个通知或目标
	            System.out.println("Advice1.after()");
	            return result;
	        }
	    }

	    static class Advice2 implements MethodInterceptor {
	        public Object invoke(MethodInvocation invocation) throws Throwable {
	            System.out.println("Advice2.before()");
	            Object result = invocation.proceed();// 调用下一个通知或目标
	            System.out.println("Advice2.after()");
	            return result;
	        }
	    }

        /****
         * 自定义拦截器 实现MethodInvocation需要重写它的方法
         * @author Administrator
         *
         */
	    static class MyInvocation implements MethodInvocation {
	        private Object target;  // 1  目标对象
	        private Method method;  //目标方法
	        private Object[] args;  //目标参数
	        List<MethodInterceptor> methodInterceptorList; // 2  切面集合
	        private int count = 1; // 调用次数

	        public MyInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> methodInterceptorList) {
	            this.target = target;
	            this.method = method;
	            this.args = args;
	            this.methodInterceptorList = methodInterceptorList;
	        }

	        @Override
	        public Method getMethod() {
	            return method;
	        }

	        @Override
	        public Object[] getArguments() {
	            return args;
	        }

	        @Override
	        public Object proceed() throws Throwable { // 调用每一个环绕通知, 调用目标
	            if (count > methodInterceptorList.size()) {
	                // 调用目标， 返回并结束递归   这是拦截器执行完毕，使用反射来执行目标方法
	                return method.invoke(target, args);
	            }
	            // 逐一调用通知, count + 1
	            MethodInterceptor methodInterceptor = methodInterceptorList.get(count++ - 1);  
	            //count-1说明的是 切面集合是从0开始的，但是调用次数是从1开始   
	            //count++是执行一次后调用次数再加1
	            return methodInterceptor.invoke(this);   
	            //拦截器执行invoke方法后，在invoke方法中又执行调用链的proceed方法，就又执行这个类的proceed方法来实现调用链的功能
	            //等所有的执行完后，再执行invoke的proceed方法后的内容，来实现先进后出的效果
	        }

	        @Override
	        public Object getThis() {
	            return target;
	        }

	        @Override
	        public AccessibleObject getStaticPart() {
	            return method;
	        }
	    }

	    public static void main(String[] args) throws Throwable {
	        Target target = new Target();
	        
	        /****
	        List<MethodInterceptor> list = List.of(   //List.of方法是Java9引入
	                new Advice1(),
	                new Advice2()
	        );
	        **/
	       List<MethodInterceptor> list = Arrays.asList(new Advice1(), new Advice2());
	        MyInvocation invocation = new MyInvocation(target, Target.class.getMethod("foo"), new Object[0], list);
	        invocation.proceed();
	    }
}
